use std::{
    ffi::{CStr, CString},
    os::raw::c_char,
    sync::{
        Arc, Mutex,
        mpsc::{self, Receiver, Sender},
    },
    thread::{self, JoinHandle},
};

use std::time::Duration;

// === FFI 定义 ===

type RustLogStrCb = extern "C" fn(*const c_char);

unsafe extern "C" {
    fn ffmpeg_main(cmdline_str: *const c_char) -> i32;
    fn ffmpeg_stop();
    fn my_av_log_set_callback(cb: RustLogStrCb);
}

// === 同步日志缓存区（仅用于 run_sync 模式） ===

lazy_static::lazy_static! {
    static ref SYNC_LOGS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
}

// === 异步日志全局发送通道（run_async 模式用） ===

lazy_static::lazy_static! {
    static ref ASYNC_LOG_SENDER: Arc<Mutex<Option<Sender<String>>>> = Arc::new(Mutex::new(None));
}

// === 同步日志回调 ===
extern "C" fn sync_log_callback(msg: *const c_char) {
    unsafe {
        if !msg.is_null() {
            if let Ok(s) = CStr::from_ptr(msg).to_str() {
                SYNC_LOGS.lock().unwrap().push(s.trim_end().to_string());
            }
        }
    }
}

// === 异步日志回调 ===
extern "C" fn async_log_callback(msg: *const c_char) {
    unsafe {
        if !msg.is_null() {
            if let Ok(s) = CStr::from_ptr(msg).to_str() {
                if let Some(sender) = &*ASYNC_LOG_SENDER.lock().unwrap() {
                    let _ = sender.send(s.trim_end().to_string());
                }
            }
        }
    }
}

// === Ffmpeg 封装结构体 ===

pub struct Ffmpeg {
    handle: Option<JoinHandle<()>>,
}

impl Ffmpeg {
    pub fn new() -> Self {
        Self { handle: None }
    }

    /// 同步执行 FFmpeg，日志自动收集，可用 get_logs() 获取
    pub fn run_sync(&self, args: Vec<&str>) {
        let cmd = CString::new(args.join(" ")).unwrap();
        SYNC_LOGS.lock().unwrap().clear();

        unsafe {
            my_av_log_set_callback(sync_log_callback);
            ffmpeg_main(cmd.as_ptr());
        }
    }

    /// 获取 run_sync 执行后的日志内容
    pub fn get_logs(&self) -> Vec<String> {
        SYNC_LOGS.lock().unwrap().clone()
    }

    /// 异步运行 FFmpeg，返回 (控制 tx, 日志 rx)
    /// 主线程可通过 tx 发送 "stop" 字符串触发 ffmpeg_stop()

    pub fn run_async(&mut self, args: Vec<&str>) -> (Sender<String>, Receiver<String>) {
        let (log_tx, log_rx) = mpsc::channel::<String>();
        // 复制了一个 Sender 给日志回调线程用，但这个 Sender 不清空就永远“持有通道”。
        //Rust 的 Receiver 在 for log in log_rx 中只有在 所有发送者全部销毁 时，才会退出
        *ASYNC_LOG_SENDER.lock().unwrap() = Some(log_tx.clone());

        let (control_tx, control_rx) = mpsc::channel::<String>();

        unsafe {
            my_av_log_set_callback(async_log_callback);
        }

        let cmd = CString::new(args.join(" ")).unwrap();

        self.handle = Some(thread::spawn(move || {
            // 控制线程监听stop指令
            let stop_handle = thread::spawn(move || {
                for msg in control_rx.iter() {
                    if msg.trim() == "stop" {
                        println!("Received stop signal, calling ffmpeg_stop()");
                        unsafe {
                            ffmpeg_stop();
                        }
                        println!("Called ffmpeg_stop(), control thread exiting");
                        break;
                    }
                }
            });

            unsafe {
                ffmpeg_main(cmd.as_ptr());
            }

            println!("ffmpeg_main returned, dropping log_tx");
            drop(log_tx); // 释放当前 sender

            // 清空全局 sender，防止它阻止日志线程退出
            *ASYNC_LOG_SENDER.lock().unwrap() = None;

            let _ = stop_handle.join();
            println!("Control thread joined, ffmpeg thread exiting");
        }));

        (control_tx, log_rx)
    }

    /// 等待异步线程退出
    pub fn wait(&mut self) {
        if let Some(h) = self.handle.take() {
            let _ = h.join();
        }
    }

    /// 主动中断 FFmpeg（适用于异步运行）
    pub fn stop(&self) {
        unsafe { ffmpeg_stop() }
    }
}

fn async_example() {
    let args = vec![
        "ffmpeg",
        "-y",
        "-probesize",
        "100M",
        // 桌面输入
        "-f",
        "gdigrab",
        "-r",
        "10",
        "-i",
        "desktop",
        // 摄像头输入
        "-f",
        "dshow",
        "-i",
        "video=\"FULL HD 1080P Webcam\"", // 注意这里不加引号
        // 滤镜合成：桌面缩放 + 摄像头缩放 + 叠加
        "-filter_complex",
        "[0]scale=1024:-1[desktop];[1]scale=160:120[cam];[desktop][cam]overlay=10:10",
        // 编码与输出设置
        "-b:v",
        "550k",
        "-c:v",
        "libx264",
        "test4.mkv",
    ];

    let mut ffmpeg = Ffmpeg::new();

    let (ctrl_tx, log_rx) = ffmpeg.run_async(args);

    // 启动日志接收线程
    let log_thread = std::thread::spawn(move || {
        for log in log_rx {
            println!("[Async Log] {}", log);
        }
        println!("Log thread exiting");
    });

    // 运行 3 秒后发送 stop 指令
    thread::sleep(Duration::from_secs(30));
    let _ = ctrl_tx.send("stop".to_string());

    ffmpeg.wait();
    let _ = log_thread.join();
    println!("=== Async FFmpeg Stopped ===");
}

fn sync_example() {
    let args = vec!["ffmpeg", "-version"];
    let ffmpeg = Ffmpeg::new();

    ffmpeg.run_sync(args);

    println!("=== Sync Logs ===");
    for log in ffmpeg.get_logs() {
        println!("{}", log);
    }
}

fn main() {
    // println!("--- Synchronous Mode ---");
    // sync_example();
    // println!("--- Synchronous Mode1 ---");
    // sync_example();

    println!("\n--- Asynchronous Mode ---");
    async_example();
}
